package com.ruge.user.service.impl;

import com.ruge.core.enums.IntegralEnum;
import com.ruge.core.response.Response;
import com.ruge.core.tool.AssertTool;
import com.ruge.core.tool.RedisKeyTool;
import com.ruge.tool.json.JsonTool;
import com.ruge.user.dao.IntegralLogRepository;
import com.ruge.user.dao.IntegralRuleRepository;
import com.ruge.user.domain.model.IntegralLog;
import com.ruge.user.domain.model.IntegralRule;
import com.ruge.user.domain.vo.IntegralLogVo;
import com.ruge.user.error.UserError;
import com.ruge.user.service.IntegralLogService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author ruge.wu
 * @since 2022/2/11 11:03
 */
@Service
public class IntegralLogServiceImpl implements IntegralLogService {

    @Resource
    private IntegralRuleRepository integralRuleRepository;
    @Resource
    private IntegralLogRepository integralLogRepository;
    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 新增积分
     *
     * @param aid          aid
     * @param integralEnum {@link IntegralEnum}
     * @return 新增积分
     */
    @Override
    public Response save(Long aid, IntegralEnum integralEnum) {
        IntegralRule integralRule = integralRuleRepository.findFirstByIntegralTypeAndIsValidTrue(integralEnum).orElse(new IntegralRule());
        AssertTool.mustNotBlack(integralRule.getId(), UserError.INTEGRAL_RULE_NOT_EXIST);

        IntegralLog build = IntegralLog.builder()
                .aid(aid)
                .integral(integralRule.getIntegral())
                .integralType(integralRule.getIntegralType())
                .integralName(integralRule.getIntegralName())
                .build();
        integralLogRepository.save(build);

        //将积分的 数据保存到redis  zset
        redisTemplate.opsForZSet().incrementScore(RedisKeyTool.buildIntegralKey(), aid, integralRule.getIntegral());
        return Response.create();
    }

    /**
     * 积分规则 初始化至mysql
     *
     * @return 积分规则初始化
     */
    @Override
    public Response initRule() {
        IntegralEnum[] values = IntegralEnum.values();
        for (IntegralEnum value : values) {
            IntegralRule build = new IntegralRule();
            build.setIntegral(value.getValue());
            build.setIntegralType(value);
            build.setIntegralName(value.getDesc());
            integralRuleRepository.save(build);
        }
        return Response.create();
    }

    /**
     * 获取前x名积分排行
     *
     * @param top x名
     * @return {@link Response}
     */
    @Override
    public Response getTop(Integer top) {
        List<Map<String, Object>> top1 = integralLogRepository.getTop(top);
        IntegralLogVo objToBean = JsonTool.getObjToBean(top1, IntegralLogVo.class);
        return Response.create(objToBean);
    }

    /**
     * 获取前x名积分排行
     *
     * @param top x名
     * @return {@link Response}
     */
    @Override
    public Response getTopFromRedis(Integer top) {
        List<IntegralLogVo> list = new ArrayList<>();
        Set<ZSetOperations.TypedTuple<Integer>> set = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyTool.buildIntegralKey(), 0, top - 1);
        ArrayList<ZSetOperations.TypedTuple<Integer>> arrayList = new ArrayList<>(set);

        for (int i = 0; i < arrayList.size(); i++) {
            ZSetOperations.TypedTuple<Integer> typedTuple = arrayList.get(i);
            IntegralLogVo build = IntegralLogVo.builder()
                    .total(typedTuple.getScore().longValue())
                    .aid(typedTuple.getValue().longValue())
                    .ranks(i + 1)
                    .build();
            list.add(build);
        }

        return Response.create(list);
    }

    /**
     * 获取指定aid的排行
     *
     * @param aid aid
     * @return {@link Response}
     */
    @Override
    public Response getRankByAid(Long aid) {
        List<Map<String, Object>> top1 = integralLogRepository.getRankByAid(aid);
        IntegralLogVo objToBean = JsonTool.getObjToBean(top1, IntegralLogVo.class);
        return Response.create(objToBean);
    }

    /**
     * 获取指定aid的排行
     *
     * @param aid aid
     * @return {@link Response}
     */
    @Override
    public Response getRankByAidFromRedis(Long aid) {
        // 获取排名
        Integer ranks = redisTemplate.opsForZSet().reverseRank(RedisKeyTool.buildIntegralKey(), aid).intValue();
        // 获取积分
        Long total = redisTemplate.opsForZSet().score(RedisKeyTool.buildIntegralKey(), aid).longValue();
        IntegralLogVo vo = new IntegralLogVo();
        vo.setAid(aid);
        vo.setRanks(ranks + 1);
        vo.setTotal(total);
        return Response.create(vo);
    }
}
